﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace WrapperTool
{
    public class TypeHelper
    {
        public const string const_wrapper = "Wrapper";
        private Type _type = null;
        private string _dynamicWrapperName = "";
        private string _firstName = "";
        private string _lastName = "";
        private Dictionary<string, string> dicUsing = new Dictionary<string, string>();
        private static Dictionary<string, object> dicNameSpace = new Dictionary<string, object>();

        public Dictionary<string, string> DicUsing
        {
            get
            {
                if (dicUsing == null)
                {
                    dicUsing = new Dictionary<string, string>();
                }
                return dicUsing;
            }
        }

        public static Dictionary<string, object> DicNameSpace
        {
            get
            {
                if (dicNameSpace == null)
                {
                    dicNameSpace = new Dictionary<string, object>();
                }
                return dicNameSpace;
            }
        }

        public void InitTypeHelper(Type type)
        {
            _type = type;
            //添加需要引入的Namespace
            if (type.Namespace != null && !dicUsing.ContainsKey(type.Namespace))
            {
                dicUsing.Add(type.Namespace, "using " + type.Namespace + ";");
            }
            //泛型处理
            //这里有个很奇怪的Bug,HardCode
            if (_type.IsGenericType || _type.Name.StartsWith("Nullable`"))
            {
                //_firstName = _type.Name.TrimEnd('&');
                //_firstName = _firstName.Substring(0, _firstName.Length - 2);
                //var arguments = _type.GetGenericArguments();
                //var streamLastName = new StringBuilder();
                //foreach (var arg in arguments)
                //{
                //    //添加需要引入的Namespace
                //    if (!dicUsing.ContainsKey(arg.Namespace))
                //    {
                //        dicUsing.Add(arg.Namespace, "using " + arg.Namespace + ";");
                //    }
                //    streamLastName.Append(arg.Name + ", ");
                //}
                //_lastName = "<" + streamLastName.CutLastCommaToString() + ">";
                GetGenericName(type, ref _firstName, ref _lastName);
            }
            else if (_type.IsArray)
            {
                //一个Bug,比如二位数组[,]
                //_firstName = _type.Name.TrimEnd('&');
                string tempName = _type.Name.TrimEnd('&');
                int index = tempName.IndexOf('[');
                _firstName = tempName.Substring(0, index);
                _lastName = tempName.Substring(index);
            }
            else
            {
                _firstName = _type.Name.TrimEnd('&');
                _lastName = "";
            }
        }

        public string GetName(Type type)
        {
            InitTypeHelper(type);
            //内嵌公用类处理
            if (_type.IsNestedPublic)
            {
                _firstName = _type.DeclaringType.Name + "." + _firstName;
            }
            return _firstName + _lastName;
        }

        public string GetFristName(Type type)
        {
            InitTypeHelper(type);
            return _firstName;
        }

        public string GetFristWrapperName(Type type)
        {
            InitTypeHelper(type);
            return _firstName + const_wrapper;
        }

        public string GetLastName(Type type)
        {
            InitTypeHelper(type);
            return _lastName;
        }

        public string GetWrapperName(Type type)
        {
            InitTypeHelper(type);
            return _firstName + const_wrapper + _lastName;
        }

        public static Dictionary<Type, string> typeNames = new Dictionary<Type, string>
        {
            {typeof(int),"int"},
            {typeof(double),"double"},
            {typeof(long),"long"},
            {typeof(string),"string"},
            {typeof(char),"char"},
            {typeof(float),"float"},
            {typeof(decimal),"decimal"},
            {typeof(uint),"uint"},
            {typeof(ulong),"ulong"},
            {typeof(ushort),"ushort"}
        };

        //在当前所指定的assembly中存在该Class的定义,返回Wrapper过的ClassName
        public string GetDynamicWrapperName(Type type)
        {
            InitTypeHelper(type);
            //if (_type.IsClass && !_type.IsAbstract && DicNameSpace.ContainsKey(_type.Namespace))
            //泛型的类型占位符T等不能Wrapper
            //if (_type.IsClass && !_type.IsAbstract && DicNameSpace.ContainsKey(_type.Namespace) && _type.FullName != null)
            //抽象类需要Wrapper
            if (typeNames.ContainsKey(type))
                return typeNames[type];
            if (_type.IsClass && DicNameSpace.ContainsKey(_type.Namespace) && !_type.IsGenericParameter
                //T[]不Wrapper
                && !(_type.IsArray && _type.FullName == null))
            {
                //在当前所指定的assembly中存在该Class的定义,返回Wrapper过的Class
                _dynamicWrapperName = _firstName + const_wrapper + _lastName;
            }
            else
            {
                _dynamicWrapperName = _firstName + _lastName;
            }
            return _dynamicWrapperName;
        }
        private bool GetGenericName(Type t, ref string firstName, ref string lastName)
        {
            if (t.IsGenericType)
            {

                string[] name = t.Name.Split('`');
                firstName = name[0];
                Type[] genTypes = t.GetGenericArguments();
                lastName = "<";
                lastName += GetGenericName(genTypes[0]);
                for (var i = 1; i < genTypes.Length; i++)
                {
                    name[0] += ", " + GetGenericName(genTypes[i]);
                }
                lastName += ">";
                return true;

            }
            return false;
        }
        private string GetGenericName(Type t)
        {
            if (t.IsGenericType)
            {

                string[] name = t.Name.Split('`');

                Type[] genTypes = t.GetGenericArguments();
                name[0] += "<";
                name[0] += GetGenericName(genTypes[0]);
                for (var i = 1; i < genTypes.Length; i++)
                {
                    name[0] += ", " + GetGenericName(genTypes[i]);
                }
                name[0] += ">";

                return name[0];
            }
            else
            {
                return new TypeHelper().GetDynamicWrapperName(t);
            }

        }

        //返回方法名,为了处理泛型方法
        public string GetMethodName(MethodInfo method)
        {
            string methodName = "";
            if (method.IsGenericMethod)
            {
                var arguments = method.GetGenericArguments();
                var streamMethodName = new StringBuilder();
                foreach (var arg in arguments)
                {
                    streamMethodName.Append(arg.Name + ", ");
                }
                methodName = method.Name + "<" + streamMethodName.CutLastCommaToString() + ">";
            }
            else
            {
                methodName = method.Name;
            }
            return methodName;
        }

        //返回泛型方法的约束条件
        public string GetMethodConstraint(MethodInfo method)
        {
            string conStr = "";
            if (method.IsGenericMethod)
            {
                var arguments = method.GetGenericArguments();
                foreach (var arg in arguments)
                {
                    var streamConstraint = new StringBuilder();
                    var constraints = arg.GetGenericParameterConstraints();
                    //这里有Bug, where class约束条件目前处理不了
                    if (constraints.Length > 0)
                    {
                        streamConstraint.Append(" where ");
                        streamConstraint.Append(arg.Name + ": ");
                        foreach (var oneCon in constraints)
                        {

                            streamConstraint.Append(GetName(oneCon) + ", ");
                        }
                    }
                    else if (arg.GenericParameterAttributes != GenericParameterAttributes.None)
                    {
                        streamConstraint.Append("where ");
                        streamConstraint.Append(arg.Name + " : ");
                    }

                    if (arg.GenericParameterAttributes != GenericParameterAttributes.None)
                    {
                        if (!arg.GenericParameterAttributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint) && arg.GenericParameterAttributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
                        {
                            streamConstraint.Append("new(), ");
                        }

                        if (arg.GenericParameterAttributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))
                        {
                            streamConstraint.Append("class, ");
                        }
                    }
                    conStr += streamConstraint.CutLastCommaToString();
                }
            }
            return conStr;
        }

        //返回泛型类的约束条件
        public string GetClassConstraint(Type type)
        {
            string conStr = "";
            if (type.IsGenericType)
            {
                var arguments = type.GetGenericArguments();
                foreach (var arg in arguments)
                {
                    var streamConstraint = new StringBuilder();
                    var constraints = arg.GetGenericParameterConstraints();
                    //这里有Bug, where class约束条件目前处理不了
                    if (constraints.Length > 0)
                    {
                        streamConstraint.Append(" where ");
                        streamConstraint.Append(arg.Name + ": ");
                        foreach (var oneCon in constraints)
                        {


                            streamConstraint.Append(GetName(oneCon) + ", ");

                        }
                    }
                    else if (arg.GenericParameterAttributes != GenericParameterAttributes.None)
                    {
                        streamConstraint.Append("where ");
                        streamConstraint.Append(arg.Name + " : ");
                    }

                    if (arg.GenericParameterAttributes != GenericParameterAttributes.None)
                    {
                        if (!arg.GenericParameterAttributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint) && arg.GenericParameterAttributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
                        {
                            streamConstraint.Append("new(), ");
                        }

                        if (arg.GenericParameterAttributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))
                        {
                            streamConstraint.Append("class, ");
                        }
                    }
                    conStr += streamConstraint.CutLastCommaToString();
                }
            }
            return conStr;
        }
    }

    public static class ExtensionHelper
    {
        //判断指定类型是否是Wrapper过的
        public static bool EndsWithWrapper(this string typeName, string const_wrapper = TypeHelper.const_wrapper)
        {
            bool hasWrapper = false;
            string tempTypeName = typeName;
            if (typeName.Length >= const_wrapper.Length)
            {
                if (typeName.Contains("<"))
                {
                    int index = typeName.IndexOf("<");
                    tempTypeName = typeName.Substring(0, index);
                }
                else if (typeName.Contains("["))
                {
                    int index = typeName.IndexOf("[");
                    tempTypeName = typeName.Substring(0, index);
                }
                hasWrapper = tempTypeName.EndsWith(const_wrapper);
            }
            return hasWrapper;
        }

        public static string CutLastCommaToString(this StringBuilder sb)
        {
            return sb.ToString().TrimEnd().TrimEnd(',');
        }

        public static bool GetCanRead(this PropertyInfo proInfo)
        {
            bool canRead = false;
            if (proInfo.CanRead)
            {
                var accessors = proInfo.GetAccessors();
                foreach (var accessor in accessors)
                {
                    if (accessor.Name.StartsWith("get_"))
                    {
                        canRead = true;
                        break;
                    }
                }
            }
            return canRead;
        }

        public static bool GetCanWrite(this PropertyInfo proInfo)
        {
            bool canWrite = false;
            if (proInfo.CanWrite)
            {
                var accessors = proInfo.GetAccessors();
                foreach (var accessor in accessors)
                {
                    if (accessor.Name.StartsWith("set_"))
                    {
                        canWrite = true;
                        break;
                    }
                }
            }
            return canWrite;
        }

    }
}
